package com.yuandian.management.service.impl;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.collection.CollUtil;
import cn.hutool.core.util.StrUtil;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import com.yuandian.api.management.entity.ConfMpAlarm;
import com.yuandian.api.management.entity.ConfMpAlarmPeriod;
import com.yuandian.api.management.entity.ConfMpService;
import com.yuandian.api.management.po.ConfMpAlarmParams;
import com.yuandian.bpm.common.core.util.R;
import com.yuandian.management.mapper.ConfMpAlarmMapper;
import com.yuandian.management.service.ConfMpAlarmPeriodService;
import com.yuandian.management.service.ConfMpAlarmService;
import com.yuandian.utils.MpGenUtil;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.Collections;
import java.util.List;
import java.util.stream.Collectors;

/**
 * 中台监控-告警配置表-Service实现
 * @author zfsn
 * @date 2023-4-18
 */
@Service
public class ConfMpAlarmServiceImpl extends ServiceImpl<ConfMpAlarmMapper, ConfMpAlarm>
		implements ConfMpAlarmService {

	@Autowired
	private ConfMpAlarmPeriodService confMpAlarmPeriodService;

	/**
	 * 分页查询
	 * @param params 中台监控-告警配置请求参数
	 * @return 通用返回对象
	 */
	@Override
	public R<Page<ConfMpAlarm>> page(ConfMpAlarmParams params) {
		Page<ConfMpAlarm> page = Page.of(params.getCurrent(), params.getSize());
		page.addOrder(params.orders()).orders().forEach(orderItem -> orderItem.setColumn(StrUtil.toUnderlineCase(orderItem.getColumn())));
		return R.ok(lambdaQuery()
				.eq(params.getServiceId() != null, ConfMpAlarm::getServiceId, params.getServiceId())
				.page(page));
	}

	/**
	 * 新增数据
	 * @param params 中台监控-告警配置请求参数
	 * @return 通用返回对象
	 */
	@Transactional(rollbackFor = Exception.class)
	@Override
	public R<Boolean> saveWrap(ConfMpAlarmParams params) {
		// 1、新增告警配置
		ConfMpAlarm confMpAlarm = BeanUtil.copyProperties(params, ConfMpAlarm.class);
		save(confMpAlarm);
		// 2、新增告警周期段配置
		Integer alarmId = confMpAlarm.getId();
		List<ConfMpAlarmPeriod> periodList = params.getPeriodList();
		periodList.forEach(period -> {
			period.setId(null);
			period.setAlarmId(alarmId);
		});
		confMpAlarmPeriodService.saveBatch(periodList);
		return R.ok(Boolean.TRUE, "新增成功");
	}

	/**
	 * 通过主键更新数据
	 * @param params 中台监控-告警配置请求参数
	 * @return 通用返回对象
	 */
	@Transactional(rollbackFor = Exception.class)
	@Override
	public R<Boolean> updateByIdWrap(ConfMpAlarmParams params) {
		// 1、更新告警周期段配置
		List<ConfMpAlarmPeriod> periodList = params.getPeriodList();
		confMpAlarmPeriodService.updateBatchById(periodList);
		// 2、更新告警配置
		ConfMpAlarm confMpAlarm = BeanUtil.copyProperties(params, ConfMpAlarm.class);
		updateById(confMpAlarm);
		return R.ok(Boolean.TRUE, "更新成功");
	}

	/**
	 * 通过主键删除数据
	 * @param idList 主键集合
	 * @return 通用返回对象
	 */
	@Transactional(rollbackFor = Exception.class)
	@Override
	public R<Boolean> removeByIdsWrap(List<Integer> idList) {
		// 1、校验请求参数
		if (CollUtil.isEmpty(idList)) {
			return R.failed("删除失败，主键集合不能为空");
		}
		// 2、根据告警id集合删除告警周期段配置
		confMpAlarmPeriodService.removeByAlarmIds(idList);
		// 3、删除告警配置
		removeByIds(idList);
		return R.ok(Boolean.TRUE, "删除成功");
	}

	/**
	 * 根据服务配置调整告警配置
	 * 1、当服务调用方式改变时
	 * @param confMpService 服务配置实体
	 * @return 通用返回对象
	 */
	@Transactional(rollbackFor = Exception.class)
	@Override
	public R<Boolean> updateByService(ConfMpService confMpService) {
		// 1、查询服务下所有的告警配置
		Integer serviceId = confMpService.getId();
		List<ConfMpAlarm> alarmList = lambdaQuery().eq(ConfMpAlarm::getServiceId, serviceId).list();
		// 2、根据服务调用方式生成默认的告警配置
		List<ConfMpAlarmParams> defaultAlarmList = MpGenUtil.genDefaultAlarm(confMpService.getInvocationMode(), serviceId);
		// 3、获取当前告警配置所有的告警编码集合，以及默认告警配置所有的告警编码集合
		List<String> alarmCodeList = alarmList.stream()
				.map(ConfMpAlarm::getAlarmCode).collect(Collectors.toList());
		List<String> defaultAlarmCodeList = defaultAlarmList.stream()
				.map(ConfMpAlarmParams::getAlarmCode).collect(Collectors.toList());
		// 3、需要删除的告警配置
		List<Integer> deleteAlarmIdList = alarmList.stream()
				.filter(alarm -> !defaultAlarmCodeList.contains(alarm.getAlarmCode()))
				.map(ConfMpAlarm::getId)
				.collect(Collectors.toList());
		// 4、需要新增的告警配置
		List<ConfMpAlarmParams> saveAlarmList = defaultAlarmList.stream()
				.filter(alarm -> !alarmCodeList.contains(alarm.getAlarmCode()))
				.collect(Collectors.toList());
		// 5、删除告警配置
		removeByIdsWrap(deleteAlarmIdList);
		// 6、新增告警配置
		saveAlarmList.forEach(this::saveWrap);
		return R.ok(Boolean.TRUE, "调整成功");
	}

	/**
	 * 根据服务id集合删除服务下的所有告警配置
	 * @param serviceIdList 服务id集合
	 * @return 通用返回对象
	 */
	@Transactional(rollbackFor = Exception.class)
	@Override
	public R<Boolean> removeByServiceIds(List<Integer> serviceIdList) {
		// 1、根据服务id集合查询所有的告警配置
		List<ConfMpAlarm> alarmList = lambdaQuery()
				.in(CollUtil.isNotEmpty(serviceIdList), ConfMpAlarm::getServiceId, serviceIdList).list();
		// 2、获取所有告警配置的id
		List<Integer> alarmIdList = alarmList.stream().map(ConfMpAlarm::getId).collect(Collectors.toList());
		// 3、通过主键删除告警配置
		return removeByIdsWrap(alarmIdList);
	}

	/**
	 * 通过告警id查询告警时间段
	 * @param alarmId 告警id
	 * @return 告警时间段集合
	 */
	@Override
	public R<List<ConfMpAlarmPeriod>> queryPeriodByAlarmId(Integer alarmId) {
		return R.ok(confMpAlarmPeriodService.lambdaQuery().eq(ConfMpAlarmPeriod::getAlarmId, alarmId).list());
	}

	/**
	 * 通过告警id更新告警时间段
	 * @param params 中台监控-告警配置请求参数
	 * @return 通用返回对象
	 */
	@Transactional(rollbackFor = Exception.class)
	@Override
	public R<Boolean> updatePeriodByAlarmId(ConfMpAlarmParams params) {
		Integer alarmId = params.getId();
		confMpAlarmPeriodService.removeByAlarmIds(Collections.singletonList(alarmId));
		List<ConfMpAlarmPeriod> periodList = params.getPeriodList();
		periodList.forEach(period -> {
			period.setId(null);
			period.setAlarmId(alarmId);
		});
		confMpAlarmPeriodService.saveBatch(periodList);
		return R.ok(Boolean.TRUE, "更新成功");
	}
}